package cn.hpclub.server.controller.admin;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

import cn.hpclub.server.model.Organization;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSONObject;
import com.jfinal.aop.Before;
import com.jfinal.aop.Clear;
import com.jfinal.core.Controller;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Model;
import com.jfinal.plugin.activerecord.Page;

import cn.hpclub.server.bean.SystemConfig;
import cn.hpclub.server.constant.Constant;
import cn.hpclub.server.constant.H5ApiConstant;
import cn.hpclub.server.interceptor.AdminInterceptor;
import cn.hpclub.server.model.Admin;
import cn.hpclub.server.security.ShiroUtils;
import cn.hpclub.server.util.CommonUtil;
import cn.hpclub.server.util.InterfaceUtil;
import cn.hpclub.server.util.RSAUtils;
import cn.hpclub.server.util.SystemConfigUtil;

/**
 * 后台类 - 管理中心基类 继承此类的子类具备基本的CRUD
 * 
 */
/**
 *
 */
@Before(AdminInterceptor.class)
public class BaseAdminController<M extends Model<M>> extends Controller{
    private static Logger       logger         = LoggerFactory.getLogger(BaseAdminController.class);
    public static final String  PAGE_NUMBER    = "pageNumber";
    public static final String  PAGE_SIZE      = "pageSize";
    public static final String  PAGER          = "pager";
    public static final String  STATUS         = "status";
    public static final String  WARN           = "warn";
    public static final String  SUCCESS        = "success";
    public static final String  ERROR          = "error";
    public static final String  MESSAGE        = "message";
    public static final String  CONTENT        = "content";

    private static final String ORG_LIST       = "orgList";

    protected String            redirectionUrl = "redirectionUrl";                                  // 操作提示后的跳转URL,为null则返回前一页

    // 排序方式
    public enum OrderType{
            asc,
            desc
    }

    private String property; // 查找属性名称
    private String keyword;  // 查找关键字
    private String orderBy;  // 排序字段
    private String orderType;// 排序方式

    public BaseAdminController(){
        // 把class的变量保存起来，不用每次去取
        this.setModelClass(getClazz());
    }

    /**
     * 获取M的class
     * 
     * @return M
     */
    @SuppressWarnings("unchecked")
    public Class<M> getClazz(){
        Type t = getClass().getGenericSuperclass();
        Type[] params = ((ParameterizedType)t).getActualTypeArguments();
        return (Class<M>)params[0];
    }

    protected Class<M> modelClass;

    public Class<M> getModelClass(){
        return modelClass;
    }

    public void setModelClass(Class<M> modelClass){
        this.modelClass = modelClass;
    }

    /**
     * 通用分页查找
     */
    public void findByPage(){
        String db = getModelClass().getSimpleName().toLowerCase();
        findByPage(db);
    }

    /**
     * 通用分页查找
     */
    public void findByPage(String db){
        String select = "select *";
        String sqlExceptSelect = "from " + db + " where 1 = 1 ";
        if(StrKit.notBlank(getProperty()) && StrKit.notBlank(getKeyword())){
            sqlExceptSelect += "and " + getProperty() + " like '%" + getKeyword() + "%'";
        }
        // sqlExceptSelect += " order by id desc ";
        Page<M> pager = getModel(getModelClass()).paginate(getParaToInt(PAGE_NUMBER, 1), getParaToInt(PAGE_SIZE, 10),
                                                           select, sqlExceptSelect);
        setAttr(PAGER, pager);
    }

    /**
     * 通用分页查找,排序,默认升序
     */
    public void findByPageOrderBy(String property){
        String db = getModelClass().getSimpleName().toLowerCase();
        findByPageOrderBy(db, property, "asc");
    }

    public org.json.JSONObject setResponseObj(int code, String msg, Object data){
        org.json.JSONObject rjson = new org.json.JSONObject();

        rjson.put(H5ApiConstant.Key.RESULT_CODE, code);
        rjson.put(H5ApiConstant.Key.MESSAGE, msg);

        if(data != null){
            rjson.put(H5ApiConstant.Key.DATA, data);
        }

        return rjson;
    }

    /**
     * 通用分页查找,排序,type:asc/desc
     */
    public void findByPageOrderBy(String property, String type){
        String db = getModelClass().getSimpleName().toLowerCase();
        findByPageOrderBy(db, property, type);
    }

    /**
     * 通用分页搜索
     * 
     * @param select
     * @param sqlExceptSelect
     */
    public void findByPageForSearch(String select, String sqlExceptSelect){
        Page<M> pager = getModel(getModelClass()).paginate(getParaToInt(PAGE_NUMBER, 1), getParaToInt(PAGE_SIZE, 10),
                                                           select, sqlExceptSelect);
        setAttr(PAGER, pager);
    }

    public ConcurrentHashMap<String, Object> getObjectSearchInfo(){
        String keywords = getPara("keywords");// 搜索条件JSON串
        logger.debug("keywords = " + keywords);
        ConcurrentHashMap<String, Object> searchMap = new ConcurrentHashMap<String, Object>();
        if(StrKit.isBlank(keywords)){
            return searchMap;
        }
        keepPara("keywords");
        try{
            JSONObject jo = JSONObject.parseObject(keywords);
            for(Entry<String, Object> item : jo.entrySet()){
                Object value = (Object)item.getValue();
                if(null != value){
                    searchMap.put(item.getKey(), value);
                }
            }
        }
        catch(Exception e){
            e.printStackTrace();
        }
        setAttrs(searchMap);
        return searchMap;
    }

    /**
     * 搜索条件封装成map
     * 
     * @return
     */
    public ConcurrentHashMap<String, String> getSearchInfo(){
        String keywords = getPara("keywords");// 搜索条件JSON串
        logger.debug("keywords = " + keywords);
        ConcurrentHashMap<String, String> searchMap = new ConcurrentHashMap<String, String>();
        if(!StrKit.notBlank(keywords)){
            return searchMap;
        }
        keepPara("keywords");
        try{
            JSONObject jo = JSONObject.parseObject(keywords);
            for(Entry<String, Object> item : jo.entrySet()){
                String value = (String)item.getValue();
                if(StrKit.notBlank(value)){
                    searchMap.put(item.getKey(), value);
                }
            }
        }
        catch(Exception e){
            e.printStackTrace();
        }
        setAttrs(searchMap);
        return searchMap;
    }

    /**
     * 保存搜索条件
     * 
     * @param searchInfo
     */
    public void setAttrs(ConcurrentHashMap<String, String> searchInfo){
        for(Entry<String, String> item : searchInfo.entrySet()){
            // System.out.println(item.getKey() + ":" + item.getValue());
            setAttr(item.getKey(), item.getValue());
        }
    }

    /**
     * 通用分页查找,排序
     */
    private void findByPageOrderBy(String db, String orderProperty, String orderType){
        String select = "select *";
        String sqlExceptSelect = "from " + db + " where 1 = 1 ";
        if(StrKit.notBlank(getProperty()) && StrKit.notBlank(getKeyword())){
            sqlExceptSelect += "and " + getProperty() + " like '%" + getKeyword() + "%'";
        }
        sqlExceptSelect += " order by " + orderProperty + " " + orderType + " ";
        Page<M> pager = getModel(getModelClass()).paginate(getParaToInt(PAGE_NUMBER, 1), getParaToInt(PAGE_SIZE, 10),
                                                           select, sqlExceptSelect);
        setAttr(PAGER, pager);
    }

    /**
     * 通用查找全部
     */
    public void getAll(){
        renderJson(Db.find("select * from " + getModelClass().getSimpleName() + " order by id asc;"));
    }

    /**
     * 通用根据id查找
     */
    public void getById(){
        renderJson(Db.findById(getModelClass().getSimpleName(), getParaToInt("id")));
    }

    /**
     * 通用新增
     * 
     */
    public void saved(Model<M> model){
        model.set("id", CommonUtil.getUUID());
        model.set("createDate", new Date());
        model.save();
    }

    /**
     * 通用修改
     * 
     */
    public void updated(Model<M> model){
        model.set("modifyDate", new Date());
        model.update();
    }

    /**
     * 通用删除 硬删除原本应该可以用这个的，不过，调试起来，好像删除失败
     * 
     * @throws Exception
     */
    public void delete() throws Exception{
        renderText(getModel(getModelClass()).delete() + "");
    }

    /**
     * @Title: deleteById
     * @Description:通用硬删除
     * @param tableName
     *            void
     */
    public void deleteById(String tableName){
        logger.debug("delete");
        // System.out.println("sys delete");
        String[] ids = getParaValues("ids");
        // System.out.println(tableName + " delete ids.len:" + ids.length);

        StringBuffer sb = new StringBuffer();
        sb.append("delete from " + tableName + " where id in(");
        if(ids.length > 0){
            for(int i = 0; i < ids.length; i++){
                // System.out.println("id:" + ids[i]);
                if(i == ids.length - 1){
                    sb.append("?");
                } else{
                    sb.append("?,");
                }
            }
            sb.append(")");
        } else{
            ajaxJsonErrorMessage("删除失败");
            return;
        }
        // System.out.println(tableName + " delete sb=" + sb);

        boolean success = Db.update(sb.toString(), (Object[])ids) > 0;
        if(success){
            ajaxJsonSuccessMessage("删除成功");
        } else{
            ajaxJsonErrorMessage("删除失败");
        }
    }

    /**
     * @Title: softlyDeleteById
     * @Description:通用软删除，暂时还没有人用，所以也没有调
     * @param tableName
     *            void
     */
    public void softlyDeleteById(String tableName){
        logger.debug("delete");
        // System.out.println("sys delete");
        String[] ids = getParaValues("ids");
        // System.out.println(tableName + " delete ids.len:" + ids.length);

        StringBuffer sb = new StringBuffer();
        sb.append("update " + tableName + " set is_deleted = 1" + " where id in(");
        if(ids.length > 0){
            for(int i = 0; i < ids.length; i++){
                // System.out.println("id:" + ids[i]);
                if(i == ids.length - 1){
                    sb.append("?");
                } else{
                    sb.append("?,");
                }
            }
            sb.append(")");
        } else{
            ajaxJsonErrorMessage("删除失败");
            return;
        }
        // System.out.println(tableName + " delete sb=" + sb);

        boolean success = Db.update(sb.toString(), (Object[])ids) > 0;
        if(success){
            ajaxJsonSuccessMessage("删除成功");
        } else{
            ajaxJsonErrorMessage("删除失败");
        }
    }

    // 获取系统配置信息
    public SystemConfig getSystemConfig(){
        return SystemConfigUtil.getSystemConfig();
    }

    public void renderSuccessMessage(String message, String url){
        setAttr(MESSAGE, message);
        setAttr(redirectionUrl, getRequest().getContextPath() + url);
        render("/admin/success.tpl");
    }

    @Clear
    public void renderErrorMessage(String message){
        genRSAKeyPair();
        setAttr("errorMessages", message);
        setAttr("systemConfig", SystemConfigUtil.getSystemConfig());
        setAttr("base", getRequest().getContextPath());
        render("/admin/admin_login.tpl");
    }

    // 输出JSON成功消息，返回null
    public void ajaxJsonSuccessMessage(String message){
        setAttr(STATUS, SUCCESS);
        setAttr(MESSAGE, message);
        renderJson();
    }

    public void ajaxJsonSuccessJson(Object o){
        setAttr(STATUS, SUCCESS);
        setAttr(MESSAGE, o);
        renderJson();
    }

    // 输出JSON错误消息，返回null
    public void ajaxJsonErrorMessage(String message){
        setAttr(STATUS, ERROR);
        setAttr(MESSAGE, message);
        renderJson();
    }

    // 输出JSON警告消息，返回null
    public void ajaxJsonWarnMessage(String message){
        Map<String, String> jsonMap = new HashMap<String, String>();
        jsonMap.put(STATUS, WARN);
        jsonMap.put(MESSAGE, message);
        renderJson(jsonMap);
    }

    public void addActionError(String error){
        setAttr("errorMessages", error);
        render("/admin/error.tpl");
    }

    /**
     * 根据表名、属性名称、属性值判断在数据库中是否唯一(若新修改的值与原来值相等则直接返回true).
     * 
     * @param tableName
     *            表名
     * @param propertyName
     *            属性名称
     * @param value
     *            属性值
     * @return boolean
     */
    public boolean isUnique(String tableName, String propertyName, String value){
        if(StrKit.notBlank(tableName) && StrKit.notBlank(propertyName) && StrKit.notBlank(value)){
            String sql = "select * from " + tableName + " where " + propertyName + " = ? ";
            return Db.findFirst(sql, value) == null;
        } else{
            return false;
        }
    }

    /**
     * 获取当前登录管理员(从数据库中加载),若未登录则返回null.
     * 
     * @return 当前登录管理员对象
     */
    public Admin loadLoginAdmin(){
        Admin admin = ShiroUtils.getLoginAdmin();
        if(admin == null){
            return null;
        } else{
            return Admin.dao.findById(admin.getStr("id"));
        }
    }

    /**
     * 获取当前登录管理员,若未登录则返回null.
     * 
     * @return 当前登录管理员名称
     */
    public String getLoginAdminName(){
        String loginAdminName = ShiroUtils.getLoginAdminName();
        if(StrKit.isBlank(loginAdminName)){
            return null;
        } else{
            return loginAdminName;
        }
    }

    /**
     * 获取当前登录管理员,若未登录则返回null.
     * 
     * @return 当前登录管理员ID
     */
    public String getLoginAdminId(){
        String loginAdminId = ShiroUtils.getLoginAdminId();
        if(StrKit.isBlank(loginAdminId)){
            return null;
        } else{
            return loginAdminId;
        }
    }

    public String getProperty(){
        property = getPara("property", "");
        return property;
    }

    public String getKeyword(){
        keyword = getPara("keyword", "");
        return keyword;
    }

    public String getOrderBy(){
        orderBy = getPara("orderBy", "createDate");
        return orderBy;
    }

    public String getOrderType(){
        orderType = getPara("orderType", OrderType.desc.name());
        return orderType;
    }

    public Map<String, Object> buildUploadReturnMsg(int status, String errorMsg){
        Map<String, Object> jsonMap = new HashMap<String, Object>();
        jsonMap.put("status", status);
        jsonMap.put("result", errorMsg);
        return jsonMap;
    }

    public void genRSAKeyPair(){
        /* 生成KeyPair */
        Map<String, Object> keyMap;
        try{
            keyMap = RSAUtils.genKeyPair();
            String publicKey = RSAUtils.getPublicKey(keyMap);
            String privateKey = RSAUtils.getPrivateKey(keyMap);

            /* 保存私钥到session */
            this.setSessionAttr(Constant.PRIVATEKEY, privateKey);

            /* 公钥给前端页面 */
            setAttr(Constant.PUBLICKEY, publicKey);
        }
        catch(Exception e){
            e.printStackTrace();
        }
    }

    /**
     * @Title: initOrgTree
     * @Description:后台管理进行搜索时，所属机构选项列表数据的加载。通过ORG_LIST返回。
     * @return int
     */
    int initOrgTree(){
        List<Entry<String, String>> orgList = InterfaceUtil.getOrgList();
        if(orgList.size() > 0){
            /* 机构树可用 */
            setAttr(ORG_LIST, orgList);
            return Integer.parseInt(orgList.get(0).getValue());
        } else{
            return 0;
        }
    }


    /**
     * @Title: initOrgTree
     * @Description:初始化机构树列表
     * @return int 返回默认查询机构ID
     */
     public int initOrgTreeWithDefaultName(){
        List<Entry<String, String>> orgList = InterfaceUtil.getOrgList();
        if(orgList.size() > 0){
            /* 机构树可用 */
            setAttr("orgs", orgList);
            return Integer.parseInt(orgList.get(0).getValue());
        } else{
            /* 无机构树,显示当前机构名称 */
            List<Entry<String, String>> list = new ArrayList<Entry<String, String>>();
            int orgId = InterfaceUtil.getOrgId();
            String orgName = Organization.dao.getOrgNameByOrgId(orgId);
            if(!StrKit.isBlank(orgName)){
                list.add(new AbstractMap.SimpleEntry<String, String>(orgName, String.valueOf(orgId)));
            }
            setAttr("orgs", list);
            return orgId;
        }
    }





}
